﻿#include "AmapViewImpl.h"

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

#include "platform/android/jni/JniHelper.h"

#define CLASS_NAME "com/myamap/tool/MyAmapViewHelper"

int CreateAMap()
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "createAMap", "()I"))
	{
		return (int)(jmi.env->CallStaticIntMethod(jmi.classID, jmi.methodID));
	}

	return 0;
}

void DestroyAMap(const int tag)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "destroyAMap", "(I)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag);
	}
}

void SetMapCenter(const int tag, double lat, double lng)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "setMapCenter", "(IDD)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag, (jdouble)lat, (jdouble)lng);
	}
}

void SetMapZoomLevel(const int tag, float level)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "setMapZoomLevel", "(IF)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag, (jfloat)level);
	}
}

void UpdateFrame(const int tag, int x, int y, int width, int height)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "setAMapRect", "(IIIII)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag, (jint)x, (jint)y, (jint)width, (jint)height);
	}
}

void SetVisible(const int tag, bool visible)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "setVisible", "(IZ)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag, (jboolean)visible);
	}
}

void AddMarker(const int tag, const string& markertag, AmapMarker* marker)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "addMarker", "(ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;DD)V"))
	{
		jstring jmarkertag = jmi.env->NewStringUTF(markertag.c_str());
		jstring jimg = jmi.env->NewStringUTF(marker->getImg().c_str());
		jstring jtitle = jmi.env->NewStringUTF(marker->getTitle().c_str());
		jstring jcontent = jmi.env->NewStringUTF(marker->getContent().c_str());

		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag, jmarkertag, jimg, (jboolean)(marker->getDraggable()), jtitle, jcontent, (jdouble)(marker->getLat()), (jdouble)(marker->getLng()));

		jmi.env->DeleteLocalRef(jmarkertag);
		jmi.env->DeleteLocalRef(jimg);
		jmi.env->DeleteLocalRef(jtitle);
		jmi.env->DeleteLocalRef(jcontent);
	}
}

void DeleteMarker(const int tag, const string& markertag)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "deleteMarker", "(ILjava/lang/String;)V"))
	{
		jstring jmarkertag = jmi.env->NewStringUTF(markertag.c_str());

		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag, jmarkertag);

		jmi.env->DeleteLocalRef(jmarkertag);
	}
}

void ClearMarkers(const int tag)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "clearMarkers", "(I)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag);
	}
}

void StartLocation(const int tag)
{
	JniMethodInfo jmi;
	if (JniHelper::getStaticMethodInfo(jmi, CLASS_NAME, "startLocation", "(I)V"))
	{
		jmi.env->CallStaticVoidMethod(jmi.classID, jmi.methodID, (jint)tag);
	}
}

extern "C"
{
	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapLoaded(JNIEnv *env, jclass, jint index) 
	{
		AmapViewImpl::onAmapLoaded((int)index);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapLocationEnd(JNIEnv *env, jclass, jint index, jint jcode, jdouble jlat, jdouble jlng, jstring jformatAddr, jstring jprovince, jstring jcity, jstring jdistrict, jstring jstreet, jstring jnumber, jstring jpoi, jstring jadcode)
	{
		string formatAddr = JniHelper::jstring2string(jformatAddr);
		string province = JniHelper::jstring2string(jprovince);
		string city = JniHelper::jstring2string(jcity);
		string district = JniHelper::jstring2string(jdistrict);
		string street = JniHelper::jstring2string(jstreet);
		string number = JniHelper::jstring2string(jnumber);
		string poi = JniHelper::jstring2string(jpoi);
		string adcode = JniHelper::jstring2string(jadcode);

		AmapViewImpl::onAmapLocationEnd((int)index, (int)jcode, (double)jlat, (double)jlng, formatAddr, province, city, district, street, number, poi, adcode);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapClicked(JNIEnv *env, jclass, jint index, jdouble jlat, jdouble jlng)
	{
		AmapViewImpl::onAmapClicked((int)index, (double)jlat, (double)jlng);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapMarkerDragStart(JNIEnv *env, jclass, jint index, jstring jmarkertag, jdouble jlat, jdouble jlng)
	{
		string markertag = JniHelper::jstring2string(jmarkertag);

		AmapViewImpl::onAmapMarkerDragStart((int)index, markertag,(double)jlat, (double)jlng);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapMarkerDrag(JNIEnv *env, jclass, jint index, jstring jmarkertag, jdouble jlat, jdouble jlng)
	{
		string markertag = JniHelper::jstring2string(jmarkertag);

		AmapViewImpl::onAmapMarkerDrag((int)index, markertag,(double)jlat, (double)jlng);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapMarkerDragEnd(JNIEnv *env, jclass, jint index, jstring jmarkertag, jdouble jlat, jdouble jlng)
	{
		string markertag = JniHelper::jstring2string(jmarkertag);

		AmapViewImpl::onAmapMarkerDragEnd((int)index, markertag,(double)jlat, (double)jlng);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapMarkerClick(JNIEnv *env, jclass, jint index, jstring jmarkertag)
	{
		string markertag = JniHelper::jstring2string(jmarkertag);

		AmapViewImpl::onAmapMarkerClick((int)index, markertag);
	}

	JNIEXPORT void JNICALL Java_com_myamap_tool_MyAmapViewHelper_onAmapMarkerInfoWindowClick(JNIEnv *env, jclass, jint index, jstring jmarkertag)
	{
		string markertag = JniHelper::jstring2string(jmarkertag);

		AmapViewImpl::onAmapMarkerInfoWindowClick((int)index, markertag);
	}
}

#else

int CreateAMap()
{
	return 0;
}
void DestroyAMap(const int tag)
{}
void SetMapCenter(const int tag, double lat, double lng)
{}
void UpdateFrame(const int tag, int x, int y, int width, int height)
{}
void SetVisible(const int tag, bool visible)
{}
void SetMapZoomLevel(const int tag, float level)
{}
void AddMarker(const int tag, const string& markertag, AmapMarker* marker)
{}
void DeleteMarker(const int tag, const string& markertag)
{}
void ClearMarkers(const int tag)
{}
void StartLocation(const int tag)
{}
#endif

static std::map<int, AmapViewImpl*> s_AMapViewImpls;
AmapViewImpl::AmapViewImpl(AmapView *mapView) : m_pAmapView(mapView)
{
	_viewTag = CreateAMap();
	s_AMapViewImpls[_viewTag] = this;
}

AmapViewImpl::~AmapViewImpl()
{
	clearMarkers();

	DestroyAMap(_viewTag);
	s_AMapViewImpls.erase(_viewTag);
}

void AmapViewImpl::setMapCenter(double lat, double lng)
{
	SetMapCenter(_viewTag, lat, lng);
}

void AmapViewImpl::startLocation()
{
	StartLocation(_viewTag);
}

void AmapViewImpl::setMapZoomLevel(float level)
{
	SetMapZoomLevel(_viewTag, level);
}

void AmapViewImpl::update(float dt)
{
	DRect cRect = m_pAmapView->convertRectToWorldSpace(m_pAmapView->getBounds());
	cRect.origin.x = s_dip_to_px(cRect.origin.x);
	cRect.origin.y = s_dip_to_px(cRect.origin.y);
	cRect.size.width = s_dip_to_px(cRect.size.width);
	cRect.size.height = s_dip_to_px(cRect.size.height);

	UpdateFrame(_viewTag, cRect.origin.x, cRect.origin.y, cRect.size.width, cRect.size.height);
}

void AmapViewImpl::setVisible(bool visible)
{
	SetVisible(_viewTag, visible);
}

void AmapViewImpl::addMarker(AmapMarker* marker)
{
	marker->retain();

	s_AmapMarkers[crossapp_format_string("%p", marker)] = marker;
	AddMarker(_viewTag, crossapp_format_string("%p", marker), marker);
}

void AmapViewImpl::deleteMarker(AmapMarker* marker)
{
	string markertag = crossapp_format_string("%p", marker);
	std::map<string, AmapMarker*>::iterator it = s_AmapMarkers.find(markertag);
	if (it != s_AmapMarkers.end())
	{
		s_AmapMarkers.erase(it);
		CC_SAFE_RELEASE_NULL(marker);
		DeleteMarker(_viewTag, markertag);
	}
}

void AmapViewImpl::clearMarkers()
{
	for (std::map<string, AmapMarker*>::iterator it = s_AmapMarkers.begin(); it != s_AmapMarkers.end(); ++it)
	{
		CC_SAFE_RELEASE_NULL(it->second);
	}

	s_AmapMarkers.clear();

	ClearMarkers(_viewTag);
}

std::map<string, AmapMarker*>& AmapViewImpl::getAllMarkers()
{
	return s_AmapMarkers;
}

void AmapViewImpl::onAmapLoaded(const int viewTag)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		AmapView* ampView = it->second->m_pAmapView;
		if (ampView && ampView->getAmapViewDelegate())
		{
			ampView->getAmapViewDelegate()->onAmapLoaded();
		}
	}
}

void AmapViewImpl::onAmapClicked(const int viewTag, double lat, double lng)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		AmapView* ampView = it->second->m_pAmapView;
		if (ampView && ampView->getAmapViewDelegate())
		{
			ampView->getAmapViewDelegate()->onAmapClicked(lat, lng);
		}
	}
}

void AmapViewImpl::onAmapLocationEnd(const int viewTag, int code, double lat, double lng, const string& formatAddr, const string& province, const string& city, const string& district, const string& street, const string& number, const string& poi, const string& adcode)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		AmapView* ampView = it->second->m_pAmapView;
		if (ampView && ampView->getAmapViewDelegate())
		{
			ampView->getAmapViewDelegate()->onAmapLocationEnd(code, lat, lng, formatAddr, province, city, district, street, number, poi, adcode);
		}
	}
}

void AmapViewImpl::onAmapMarkerDragStart(const int viewTag, const string& markertag, double lat, double lng)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		std::map<string, AmapMarker*>::iterator mIt = it->second->getAllMarkers().find(markertag);
		if (mIt != it->second->getAllMarkers().end())
		{
			AmapView* ampView = it->second->m_pAmapView;
			if (ampView && ampView->getAmapViewDelegate())
			{
				ampView->getAmapViewDelegate()->onAmapMarkerDragStart(mIt->second, lat, lng);
			}
		}
	}
}

void AmapViewImpl::onAmapMarkerDrag(const int viewTag, const string& markertag, double lat, double lng)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		std::map<string, AmapMarker*>::iterator mIt = it->second->getAllMarkers().find(markertag);
		if (mIt != it->second->getAllMarkers().end())
		{
			AmapView* ampView = it->second->m_pAmapView;
			if (ampView && ampView->getAmapViewDelegate())
			{
				ampView->getAmapViewDelegate()->onAmapMarkerDrag(mIt->second, lat, lng);
			}
		}
	}
}

void AmapViewImpl::onAmapMarkerDragEnd(const int viewTag, const string& markertag, double lat, double lng)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		std::map<string, AmapMarker*>::iterator mIt = it->second->getAllMarkers().find(markertag);
		if (mIt != it->second->getAllMarkers().end())
		{
			AmapView* ampView = it->second->m_pAmapView;
			if (ampView && ampView->getAmapViewDelegate())
			{
				ampView->getAmapViewDelegate()->onAmapMarkerDragEnd(mIt->second, lat, lng);
			}
		}
	}
}

void AmapViewImpl::onAmapMarkerClick(const int viewTag, const string& markertag)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		std::map<string, AmapMarker*>::iterator mIt = it->second->getAllMarkers().find(markertag);
		if (mIt != it->second->getAllMarkers().end())
		{
			AmapView* ampView = it->second->m_pAmapView;
			if (ampView && ampView->getAmapViewDelegate())
			{
				ampView->getAmapViewDelegate()->onAmapMarkerClick(mIt->second);
			}
		}
	}
}

void AmapViewImpl::onAmapMarkerInfoWindowClick(const int viewTag, const string& markertag)
{
	std::map<int, AmapViewImpl*>::iterator it = s_AMapViewImpls.find(viewTag);
	if (it != s_AMapViewImpls.end())
	{
		std::map<string, AmapMarker*>::iterator mIt = it->second->getAllMarkers().find(markertag);
		if (mIt != it->second->getAllMarkers().end())
		{
			AmapView* ampView = it->second->m_pAmapView;
			if (ampView && ampView->getAmapViewDelegate())
			{
				ampView->getAmapViewDelegate()->onAmapMarkerInfoWindowClick(mIt->second);
			}
		}
	}
}
